home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
System Booster
/
System Booster.iso
/
Archives
/
ForCLI
/
ccd_3_2.lha
/
ccd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-04
|
16KB
|
697 lines
/*
* ccd.c
*/
/* $Id: ccd.c,v 1.24 1993/07/03 18:41:52 beust Exp $ */
static char __version[] = "\0$VER: ccd 3.2 (03-Jul-93)";
#define EXTRAHELP "ccd 3.2, by Cédric BEUST (beust@sophia.inria.fr) $Date: 03-Jul-93\n\n"
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/amigaguide.h>
#include <intuition/intuition.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/amigaguide_protos.h>
#include "ccd.h"
#define GRAPHICS
#define min(a,b) (a < b ? a : b)
#ifndef NEW
#define NEW(v, t) v = (t *) malloc(sizeof(*v))
#endif
#define D(x) x
#define IntuitionBase gv -> IntuitionBase
/****************************************************************************/
/* Private functions */
/****************************************************************************/
static Entry
locateDir(struct GlobalVars *gv, char *dir, DataBase db, BOOL partial)
/* Return the path for the fragment given, if any, in database. partial */
/* is true if only the partial dir must be returned */
{
Entry result = NULL, entry = NULL;
int match = 0;
char *p, *onedir, pat1[128], pat3[128];
char p1[300], p3[300];
sprintf(pat1, "#?(/|:)%s(/|)", dir);
sprintf(pat3, "#?%s#?", dir);
ParsePatternNoCase(pat1, p1, 300);
ParsePatternNoCase(pat3, p3, 300);
/* Give priority to "exact matches" (e.g. DH0:l instead of DH0:Applications) */
/* match = 1 if approximate match, 2 if exact match */
while (! DB_EndOfDataBase(db) && match != 2) {
int i;
entry = DB_NextEntry(db);
p = entry -> fullPath;
if (MatchPatternNoCase(p1, p)) {
match = 2;
result = entry;
}
else if (MatchPatternNoCase(p3, p)) {
match = (partial ? 2 : 1);
result = entry;
}
}
return result;
}
static BPTR
getLock(struct GlobalVars *gv, char *name, long code)
{
BPTR *locklist = gv -> lockList;
int lockpt = gv -> lockpt;
locklist[lockpt] = Lock(name, code);
if (locklist[lockpt])
return locklist[lockpt++];
else
return 0;
}
static void
unlock(BPTR lock)
{
/*
UnLock(lock);
*/
}
/*
static void
freeAllLocks()
{
int i;
for (i = 0; i < lockpt; i++)
UnLock(locklist[i]);
}
*/
static char *
reverse(char *s)
/* Return the string s backwards (modify s)*/
{
register char c;
char *result = s + strlen(s) - 1, *r2 = s;
while (result > s) {
c = *result;
*result = *s;
*s = c;
s++; result--;
}
return(r2);
}
#ifdef A
int
mystricmp(char *bigdir, char *shortdir)
/* Check if shortdir is part of the path bigdir, return 0 if it is */
{
char t[50], *pt = t, *ps;
int i = 0;
while (*bigdir) {
while (*bigdir && *bigdir != ':' && *bigdir != '/' && *bigdir != '\n')
*pt++ = *bigdir++;
if (*bigdir) bigdir++;
*pt++ = '\0';
pt = t;
}
/* Now, we must see if shortdir is included in t */
for (i = 0; i <= strlen(t) - strlen(shortdir); i++) {
pt = &t[i]; ps = shortdir;
while (*pt && *ps && (*pt | 0x20) == (*ps | 0x20)) {
ps++; pt++;
};
if (*pt == 0 || *ps == 0) return(0); /* match! */
}
return(1);
}
#endif
static void
myputs(char *s)
{
Write(Output(), s, strlen(s));
}
static void
readDirs(char *dir, FILE *f)
{
BPTR lock;
struct FileInfoBlock info, *fib;
lock = Lock(dir, ACCESS_READ);
if (lock == 0) {
fprintf(stderr,"*** Yup! Couldn't lock %s\n", dir);
return;
}
fib = (struct FileInfoBlock *) Examine(lock, &info);
fib = &info;
while (1) {
if (ExNext(lock, fib) == 0) break;
if (fib -> fib_DirEntryType > 0) {
char t[50],c;
strcpy(t, dir);
if ((c = t[strlen(t) - 1]) != ':' && c != '/')
strcat(t,"/");
strcat(t, fib -> fib_FileName);
fprintf(f, "%s\n", t);
readDirs(t,f);
}
}
unlock(lock);
}
static int
writeConfigFile(struct GlobalVars *gv, char **dirname, int ndirs, char *mode)
/* Update the config file with the list of dirs (dirname) of length ndirs */
{
char *file = gv -> prefs.configFile;
FILE *f = fopen(file, mode);
char *tempFile = "t:.cdconfig.unsorted";
char command[128];
int i;
if (f == NULL) {
fprintf(stderr, "*** Couldn't open '%s (%s)', maybe an assign is missing?\n",
file, mode);
return(0);
}
printf("%s with", file);
for (i = 0; i < ndirs; i++) {
printf(" %s", *dirname);
fflush(stdout);
fprintf(f, "%s\n", *dirname);
readDirs(*dirname++, f);
}
printf(" -- done!\n");
fclose(f);
sprintf(command, "copy %s %s", file, tempFile);
if (SystemTags(command, TAG_DONE) == 0) {
DeleteFile(file);
sprintf(command, "sort %s %s", tempFile, file);
if (SystemTags(command, TAG_DONE) != 0) {
fprintf(stderr, "*** couldn't sort %s %s\n", tempFile, file);
sprintf(command, "copy %s %s", tempFile, file);
}
}
else {
fprintf(stderr, "*** couldn't copy %s to %s\n", file, tempFile);
}
}
/****************************************************************************/
/* Public functions */
/****************************************************************************/
int
updateConfigFile(struct GlobalVars *gv, char **dirname, int ndirs)
{
printf("Updating ");
return writeConfigFile(gv, dirname, ndirs, "a");
}
int
createConfigFile(struct GlobalVars *gv, char **dirname, int ndirs)
{
printf("Creating ");
return writeConfigFile(gv, dirname, ndirs, "w");
}
void
updatePrompt(char *currentdir)
/* Update the concerned field with the new current dir */
/* This routine is for users of wshell or such, thar display this name */
/* as the shell prompt. */
/* This trick was previously pointed to me by Henry J. Cobb on Usenet */
/* for my 'find' program (another great utility of mine :-)). */
/* Let him be thanked again! */
{
struct Process *pr = (struct Process *) FindTask(0L);
struct CommandLineInterface *cli = (struct CommandLineInterface *) pr -> pr_CLI;
char *p;
int n;
n = (int) cli;
n = n << 2;
cli = (struct CommandLineInterface *) n;
n = (int) cli -> cli_SetName;
n = n << 2;
p = (char *) n;
*p++ = strlen(currentdir); /* it is a BSTR, so length first */
while (*currentdir) *p++ = *currentdir++; /* don't add '\0' */
}
#ifdef A
void
getRealName(struct GlobalVars *gv, BPTR lock, char *result)
/* This is a very useful function! Put in result path of lock */
/* Assume lock is not null */
/* Result always device:dir/dir/... */
{
char *p = result;
struct FileInfoBlock ib;
assert(lock);
if (gv -> prefs.noExpand) return;
Examine(lock, &ib);
strcpy(result, reverse(ib.fib_FileName));
strcat(result, "/");
while (lock) {
lock = ParentDir(lock);
if (lock) {
Examine(lock, &ib);
strcat(result, reverse(ib.fib_FileName));
strcat(result,"/");
unlock(lock);
}
}
p = &p[strlen(p) - 1];
*p-- = '\0';
while (*p != '/') p--;
*p = ':';
reverse(result);
}
#endif
void
changeDir(struct GlobalVars *gv, char *dir, int occ)
/* The main function to change to the fragment of dir given, */
/* to the occ'th (first = 1) occurence found in the config file */
/* New 1.3: first, try to cd right into 'dir' */
{
char actualdir[256];
BPTR lock;
DB_Rewind(gv -> db);
strcpy(actualdir, dir);
if ((lock = Lock(actualdir, ACCESS_READ))) { /* can we cd directly? */
BPTR old;
NameFromLock(lock, actualdir, 256);
lock = getLock(gv, actualdir, ACCESS_READ);
if (gv -> prefs.verbose)
printf("Current directory is now %s\n", actualdir);
SetCurrentDirName(actualdir);
old = CurrentDir(lock); /* yes! Do it and end */
/*
UnLock(lock);
UnLock(old);
*/
return;
}
/* no, dir is a path fragment */
while (occ--) {
Entry entry = locateDir(gv, dir, gv -> db, TRUE);
strcpy(actualdir, entry -> fullPath);
}
if (actualdir[0]) {
lock = Lock(actualdir, ACCESS_READ);
if (lock == 0) {
fprintf(stderr,
"*** Couldn't cd to %s, '%s' probably outdated (re-run ccd create)\n",
actualdir, gv -> prefs.configFile);
exit(0);
}
if (gv -> prefs.noExpand)
strcpy(actualdir, dir);
else
NameFromLock(lock, actualdir, 256);
/*
getRealName(gv, lock, actualdir);
*/
if (gv -> prefs.verbose)
printf("Current directory is now %s\n", actualdir);
CurrentDir(lock);
SetCurrentDirName(actualdir);
/*
updatePrompt(actualdir);
*/
unlock(lock);
}
else
printf("%s: no such dir\n", dir);
}
void
showAmbiguities(struct GlobalVars *gv, char *dir)
{
Entry entry;
DB_Rewind(gv -> db);
while ((entry = locateDir(gv, dir, gv -> db, TRUE))) {
myputs(entry -> fullPath);
myputs("\n");
}
}
void
nthdir(char *dir, char *path, int n)
/* Path is 'volume:a/b/c' */
/* Return in dir the nth dir in it (e.g. with n=2, it's b) */
{
char *dirhead = dir;
while (*path && *path != ':') path++;
if (*path == ':') {
path++;
while (*path) {
while (*path && *path != '/') {
*dir++ = *path++;
}
if (*(dir - 1) == '\n') dir--;
*dir++ = '\0';
if (*path == '/') path++;
if (n == 1) return;
else {
n--; dir = dirhead;
}
}
}
else {
printf("nthdir: problem\n");
exit(0);
}
}
static void
freeEntry(Entry entry)
{
free(entry -> name);
}
static int
countCharsInString(char *s, char *set)
/* Return number of occurences of the chars in set in string s */
{
int result = 0;
while (*s) {
if (stpchr(set, *s)) result++;
/*
char *p = set;
while (*p) {
if (*s == *p++) result++;
}
*/
s++;
}
return result;
}
static int
pathParts(char *dir)
/* Return # of path parts (e.g. ram: -> 1, ram:env -> 2, ram:env/s -> 3 */
{
int result = countCharsInString(dir, ":/");
if (strcmp(PathPart(dir), "")) result++;
return result;
}
static int
returnNextLine(struct GlobalVars *gv, FILE *f, char *buffer, int size)
{
int result = 0, i;
if (feof(f))
result = 0;
else {
fgets(buffer, size, f);
i = strlen(buffer) - 1;
if (buffer[i] == '\n')
buffer[i] = '\0'; /* strip trailing \n */
result = i;
}
return result;
}
static void
buildAntiDataBase(struct GlobalVars *gv)
/* Build the anti database (if the file exists) */
{
FILE *f = fopen(gv -> prefs.antiConfigFile, "r");
int l = 1;
char line[256];
DataBase db;
struct _Entry entry;
if (f) {
gv -> antidb = db = DB_NewDataBase(sizeof(struct _Entry), freeEntry);
while (returnNextLine(gv, f, line, 256)) {
entry.spaces = "";
entry.name = entry.fullPath = strdup(line);
entry.line = l++;
DB_AddEntry(db, & entry);
}
fclose(f);
}
}
static BOOL
isDirectoryBelow(char *dir1, char *dir2)
/* Is dir2 below dir1? */
{
BOOL result;
if (strlen(dir1) == 0) result = FALSE;
else {
if (strnicmp(dir1, dir2, strlen(dir1)) == 0)
result = TRUE;
else
result = FALSE;
}
return result;
}
static int
buildMainDataBase(struct GlobalVars *gv, DataBase db)
{
int result = 0, line = 1, n;
static char onedir[256], spaces[256], fullLine[256];
FILE *f = fopen(gv -> prefs.configFile, "r");
struct _Entry entry;
int i;
buildAntiDataBase(gv);
if (f == NULL) {
fprintf(stderr, "*** couldn't open '%s'\n", gv -> prefs.configFile);
result = 1;
}
else {
BOOL skip = NULL;
while (returnNextLine(gv, f, onedir, 256)) {
if (gv -> antidb) {
DataBase adb = gv -> antidb;
Entry anti;
DB_Rewind(adb);
skip = FALSE;
while (! DB_EndOfDataBase(adb) && ! skip) {
anti = DB_NextEntry(adb);
if (isDirectoryBelow(anti -> name, onedir)) {
skip = TRUE;
}
}
}
if (! skip) {
n = pathParts(onedir);
strcpy(spaces, "");
for (i=0; i<n; i++) strcat(spaces, " ");
sprintf(fullLine, "%s%s", spaces, onedir);
entry.spaces = strdup(spaces);
entry.fullPath = strdup(onedir);
entry.name = strdup(n == 1 ? onedir : (char *) FilePart(onedir));
entry.line = line++;
DB_AddEntry(db, & entry);
}
}
fclose(f);
}
return result;
}
static DataBase
buildAmbiguitiesDataBase(struct GlobalVars *gv, char *dir)
/* Build a database made of ambiguities only */
{
int line = 1;
char *fullPath;
DataBase gdb = gv -> db, result;
struct _Entry entry, *entry2;
result = DB_NewDataBase(sizeof(struct _Entry), freeEntry);
DB_Rewind(gdb);
while (entry2 = locateDir(gv, dir, gdb, TRUE)) {
entry.fullPath = strdup(entry2 -> fullPath);
entry.name = entry.fullPath;
entry.spaces = ""; /* no spaces displayed when displaying ambiguities */
entry.line = line++;
DB_AddEntry(result, & entry);
}
return result;
}
void
readEnvironment(struct GlobalVars *gv, int argc, char **argv)
{
struct CSource cs;
struct RDArgs rda, *rda2;
struct Prefs result;
memset(& result, 0, sizeof(result));
gv -> prefs.configFile = CCD_FILE_DEFAULT_CONFIG;
gv -> prefs.antiConfigFile = CCD_FILE_DEFAULT_ANTI_CONFIG;
if (argc) { /* called from CLI */
memset(& rda, 0, sizeof(rda));
rda.RDA_ExtHelp = EXTRAHELP;
rda2 = ReadArgs(gv -> usage, (LONG *) & result, & rda);
if (rda2 == NULL)
fprintf(stderr, "Erreur: %s\n", gv -> usage);
/* We have to copy any returned value, its reference is not safe */
if (result.noExpand) gv -> prefs.noExpand = TRUE;
if (result.showAmbiguities) gv -> prefs.showAmbiguities = TRUE;
if (result.update) gv -> prefs.update = TRUE;
if (result.create) gv -> prefs.create = TRUE;
if (result.gui) gv -> prefs.gui = TRUE;
if (result.verbose) gv -> prefs.verbose = TRUE;
if (result.dirs) {
char **p = result.dirs;
int i=0;
while (p[i]) i++;
gv -> prefs.dirs = (char **) malloc(sizeof(char *) * i);
i = 0;
p = result.dirs;
while (p[i]) {
gv -> prefs.dirs[i] = strdup(p[i]); i++;
}
gv -> dirCount = i;
}
FreeArgs(rda2);
}
}
int
main(int argc, char **argv)
{
struct GlobalVars gv;
struct Prefs prefs;
int i = 1, line = 1;
char *dir = NULL;
memset(& gv, 0, sizeof(gv));
gv.usage = "Create=-c/S,Update=u/S,ConfigFile=-cf/K,AntiConfigFile=-acf/K,Noexpand=-b/S,ShowAmbiguities=-s/S,GUI=-g/S,Verbose=-v/S,Dirs/M";
gv.actualLine = 1;
readEnvironment(& gv, argc, argv);
prefs = gv.prefs;
if (prefs.dirs)
dir = prefs.dirs[0];
if (prefs.create || prefs.update || prefs.noExpand ||
prefs.showAmbiguities || prefs.gui || dir) { /* shortcut */
gv.db = DB_NewDataBase(sizeof(struct _Entry), freeEntry);
buildMainDataBase(& gv, gv.db);
}
if (prefs.gui) {
char var[128];
DataBase db = gv.db;
if (prefs.showAmbiguities && dir) {
db = buildAmbiguitiesDataBase(& gv, dir);
}
DeleteVar(CCD_VAR_LAST_DIR, GVF_GLOBAL_ONLY);
displayTree(& gv, db);
if (GetVar(CCD_VAR_LAST_DIR, var, 128, GVF_GLOBAL_ONLY) == -1)
fprintf(stderr, "Aborted\n");
else {
changeDir(& gv, var, 1);
}
}
else if (prefs.update) {
updateConfigFile(& gv, prefs.dirs, gv.dirCount);
}
else if (prefs.create) {
createConfigFile(& gv, prefs.dirs, gv.dirCount);
}
else if (prefs.showAmbiguities) {
char *var = dir;
if (! var) {
fprintf(stderr, "You must specify a directory to change to\nAborted\n");
}
else {
int n = 1;
if (isdigit(prefs.dirs[1][0])) { /* an occurence was given */
n = atoi(prefs.dirs[1]);
changeDir(& gv, var, n);
}
else
showAmbiguities(& gv, var);
}
}
else if (!prefs.gui && dir == NULL) {
char currentDir[256];
GetCurrentDirName(currentDir, 256);
printf("%s\n", currentDir);
}
else {
char *var = dir;
changeDir(& gv, var, 1);
if (SetVar(CCD_VAR_LAST_DIR, var, strlen(var), GVF_GLOBAL_ONLY) == 0) {
BPTR lock;
lock = CreateDir("ENV:CCD");
if (SetVar(CCD_VAR_LAST_DIR, var, strlen(var), GVF_GLOBAL_ONLY) == 0) {
fprintf(stderr, "*** couldn't set variable %s\n", CCD_VAR_LAST_DIR);
}
}
}
return 0;
}